package com.fuyun.microservice.connect.impl;

import com.fuyun.microservice.connect.SessionStore;
import com.fuyun.microservice.connect.pojo.ClientEndpoint;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.api.map.event.EntryCreatedListener;
import org.redisson.api.map.event.EntryEvent;
import org.redisson.api.map.event.EntryRemovedListener;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@Primary
public class RMapSessionStoreImpl implements SessionStore {
    final static ConcurrentMap<Integer, Channel> LOCAL_CHANNELS = new ConcurrentHashMap<>();
    private final RMapCache<String, ClientEndpoint> clientEPS;

    public RMapSessionStoreImpl(RedissonClient redissonClient) {
        this.clientEPS = redissonClient.getMapCache("gate-socket-clients");
        this.clientEPS.addListener(new EntryCreatedListener() {
            @Override
            public void onCreated(EntryEvent entryEvent) {
                log.debug("session created:{},{}", entryEvent.getKey(), entryEvent.getValue());
            }
        });

        this.clientEPS.addListener(new EntryRemovedListener() {
            @Override
            public void onRemoved(EntryEvent entryEvent) {
                log.debug("session removed:{}", entryEvent.getKey());
            }
        });
    }


    @Override
    public List<ClientEndpoint> all() {
        return clientEPS.values().stream().collect(Collectors.toList());
    }

    @Override
    public void add(Channel channel, ClientEndpoint clientEndpoint) {
        clientEPS.put(keyOfChannel(channel), clientEndpoint,5,TimeUnit.DAYS);
        LOCAL_CHANNELS.put(clientEndpoint.getClientId(),channel);
    }

    @Override
    public void remove(Channel channel) {
        ClientEndpoint clientEndpoint = clientEPS.remove(keyOfChannel(channel));
        if (clientEndpoint != null) {
            LOCAL_CHANNELS.remove(clientEndpoint.getClientId());
        }
    }

    @Override
    public ClientEndpoint getClient(Channel channel) {
        return clientEPS.get(keyOfChannel(channel));
    }

    @Override
    public Channel getChannel(int clientId) {
        return LOCAL_CHANNELS.get(clientId);
    }


    private String keyOfChannel(Channel channel) {
        InetSocketAddress socketAddress = (InetSocketAddress) channel.remoteAddress();
        return String.format("%s-%d", socketAddress.getAddress().getHostAddress(), socketAddress.getPort());
    }

}
